home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / news / nntp / nntplink3.1.0 / tcpconn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-25  |  8.8 KB  |  385 lines

  1. /*
  2.  - Routines to open a TCP connection
  3.  *
  4.  * New version that supports the old (pre 4.2 BSD) socket calls,
  5.  * and systems with the old (pre 4.2 BSD) hostname lookup stuff.
  6.  * Compile-time options are:
  7.  *
  8.  *    NONETDB        - old hostname lookup with rhost()
  9.  *    OLDSOCKET    - different args for socket() and connect()
  10.  *    DKHOST        - for DKHOST support
  11.  *
  12.  * Erik E. Fair <fair@ucbarpa.berkeley.edu>
  13.  *
  14.  */
  15.  
  16. #include "conf.h"
  17.  
  18. #ifdef DKHOST
  19. #include <dk.h>
  20. #endif
  21. #include <sys/socket.h>
  22. #ifdef FAKESYSLOG
  23. #include "fsyslog.h"
  24. #else
  25. #include <syslog.h>
  26. #endif
  27. #include <netinet/in.h>
  28. #include <ctype.h>
  29. #include "readline.h"
  30. #include "nntplink.h"
  31.  
  32. extern char *Prog_name;
  33. extern int Nntp_port;
  34.  
  35. #ifdef    EXCELAN
  36. #define    NONETDB
  37. #define    OLDSOCKET
  38. #endif
  39.  
  40. #ifdef    NONETDB
  41. #define    IPPORT_NNTP    119        /* NNTP is on TCP port 119 */
  42. #else
  43. #include <netdb.h>
  44. #endif
  45.  
  46. #ifndef    htons
  47. extern    unsigned short    htons();
  48. #endif
  49. #ifndef    NONETDB
  50. extern    char    *inet_ntoa();
  51. extern    unsigned long    inet_addr();
  52. #else
  53. /*
  54.  * inet_addr for EXCELAN (which does not have it!)
  55.  *
  56.  */
  57. unsigned long
  58. inet_addr(cp)
  59. register char    *cp;
  60. {
  61.     unsigned long val, base, n;
  62.     register char c;
  63.     unsigned long octet[4], *octetptr = octet;
  64. #ifndef    htonl
  65.     extern    unsigned long    htonl();
  66. #endif
  67. again:
  68.     /*
  69.      * Collect number up to ``.''.
  70.      * Values are specified as for C:
  71.      * 0x=hex, 0=octal, other=decimal.
  72.      */
  73.     val = 0; base = 10;
  74.     if (*cp == '0')
  75.       base = 8, cp++;
  76.     if (*cp == 'x' || *cp == 'X')
  77.       base = 16, cp++;
  78.     while (c = *cp) {
  79.     if (isdigit(c)) {
  80.         val = (val * base) + (c - '0');
  81.         cp++;
  82.         continue;
  83.     }
  84.     if (base == 16 && isxdigit(c)) {
  85.         val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
  86.         cp++;
  87.         continue;
  88.     }
  89.     break;
  90.     }
  91.     if (*cp == '.') {
  92.     /*
  93.      * Internet format:
  94.      *    a.b.c.d
  95.      *    a.b.c    (with c treated as 16-bits)
  96.      *    a.b    (with b treated as 24 bits)
  97.      */
  98.     if (octetptr >= octet + 4)
  99.       return FAIL;
  100.     *octetptr++ = val, cp++;
  101.     goto again;
  102.     }
  103.     /*
  104.      * Check for trailing characters.
  105.      */
  106.     if (*cp && !isspace(*cp))
  107.       return FAIL;
  108.     *octetptr++ = val;
  109.     /*
  110.      * Concoct the address according to
  111.      * the number of octet specified.
  112.      */
  113.     n = octetptr - octet;
  114.     switch (n) {
  115.  
  116.       case 1:                /* a -- 32 bits */
  117.     val = octet[0];
  118.     break;
  119.  
  120.       case 2:                /* a.b -- 8.24 bits */
  121.     val = (octet[0] << 24) | (octet[1] & 0xffffff);
  122.     break;
  123.  
  124.       case 3:                /* a.b.c -- 8.8.16 bits */
  125.     val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
  126.       (octet[2] & 0xffff);
  127.     break;
  128.  
  129.       case 4:                /* a.b.c.d -- 8.8.8.8 bits */
  130.     val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
  131.       ((octet[2] & 0xff) << 8) | (octet[3] & 0xff);
  132.     break;
  133.  
  134.       default:
  135.     return FAIL;
  136.     }
  137.     val = htonl(val);
  138.     return val;
  139. }
  140.  
  141. char *
  142. inet_ntoa(in)
  143. struct in_addr in;
  144. {
  145.     static char address[20];
  146.  
  147.     sprintf(address, "%u.%u.%u.%u",
  148.         (in.s_addr>>24)&0xff,
  149.         (in.s_addr>>16)&0xff,
  150.         (in.s_addr>>8 )&0xff,
  151.         (in.s_addr    )&0xff);
  152.     return address;
  153. }
  154. #endif    /* NONETDB */
  155.  
  156. /*
  157.  * Take the name of an internet host in ASCII (this may either be its
  158.  * official host name or internet number (with or without enclosing
  159.  * backets [])), and return a list of internet addresses.
  160.  *
  161.  * returns NULL for failure to find the host name in the local database,
  162.  * or for a bad internet address spec.
  163.  */
  164. unsigned long **
  165.   name_to_address(host)
  166. char    *host;
  167. {
  168.     static    unsigned long    *host_addresses[2];
  169.     static    unsigned long    haddr;
  170.     
  171.     if (host == NULL) {
  172.     return NULL;
  173.     }
  174.  
  175.     host_addresses[0] = &haddr;
  176.     host_addresses[1] = NULL;
  177.  
  178.     /*
  179.      * Is this an ASCII internet address? (either of [10.0.0.78] or
  180.      * 10.0.0.78). We get away with the second test because hostnames
  181.      * and domain labels are not allowed to begin in numbers.
  182.      * (cf. RFC952, RFC882).
  183.      */
  184.     if (*host == '[' || isdigit(*host)) {
  185.     char    namebuf[128];
  186.     register char    *cp = namebuf;
  187.  
  188.     /*
  189.      * strip brackets [] or anything else we don't want.
  190.      */
  191.     while(*host != '\0' && cp < &namebuf[sizeof(namebuf) - 1]) {
  192.         if (isdigit(*host) || *host == '.')
  193.           *cp++ = *host++;    /* copy */
  194.         else
  195.           host++;            /* skip */
  196.     }
  197.     *cp = '\0';
  198.     haddr = inet_addr(namebuf);
  199.     return &host_addresses[0];
  200.     } else {
  201. #ifdef    NONETDB
  202.     extern    unsigned long    rhost();
  203.  
  204.     /* lint is gonna bitch about this (comparing an unsigned?!) */
  205.     if ((haddr = rhost(&host)) == FAIL)
  206.       return NULL;    /* no such host */
  207.     return &host_addresses[0];
  208. #else
  209.     struct hostent    *hstp = gethostbyname(host);
  210.  
  211.     if (hstp == NULL) {
  212.         return NULL;    /* no such host */
  213.     }
  214.  
  215.     if (hstp->h_length != sizeof(unsigned long))
  216.       abort();    /* this is fundamental */
  217. #ifndef    h_addr
  218.     /* alignment problems (isn't dbm wonderful?) */
  219.     memcpy((caddr_t)&haddr, (caddr_t)hstp->h_addr, sizeof(haddr));
  220.     return &host_addresses[0];
  221. #else
  222.     return (unsigned long **)hstp->h_addr_list;
  223. #endif    /* h_addr */
  224. #endif    /* NONETDB */
  225.     }
  226. }
  227.  
  228. /*
  229.  * Get a service port number from a service name (or ASCII number)
  230.  *
  231.  * Return zero if something is wrong (that's a reserved port)
  232.  */
  233. #ifdef    NONETDB
  234. static struct Services {
  235.     char    *name;
  236.     unsigned short    port;
  237. } Services[] = {
  238.     {"nntp",    IPPORT_NNTP},        /* RFC977 */
  239.     {"smtp",    IPPORT_SMTP},        /* RFC821 */
  240.     {"name",    IPPORT_NAMESERVER},    /* RFC881, RFC882, RFC883 */
  241.     {"time",    IPPORT_TIMESERVER},    /* RFC868 */
  242.     {"echo",    IPPORT_ECHO},        /* RFC862 */
  243.     {"discard",    IPPORT_DISCARD},    /* RFC863 */
  244.     {"daytime",    IPPORT_DAYTIME},    /* RFC867 */
  245.     {"login",    IPPORT_LOGINSERVER},    /* N/A - 4BSD specific */
  246. };
  247. #endif    /* NONETDB */
  248.  
  249. unsigned short
  250.   gservice(serv, proto)
  251. char    *serv, *proto;
  252. {
  253.     if (serv == NULL || proto == NULL)
  254.       return (unsigned short)0;
  255.  
  256.     if (isdigit(*serv)) {
  257.     return htons((unsigned short)(atoi(serv)));
  258.     } else {
  259. #ifdef    NONETDB
  260.     register int    i;
  261.  
  262.     for(i = 0; i < (sizeof(Services) / sizeof(struct Services)); i++) {
  263.         if (strcmp(serv, Services[i].name) == 0)
  264.           return htons(Services[i].port);
  265.     }
  266.     return (unsigned short)0;
  267. #else
  268.     struct servent    *srvp = getservbyname(serv, proto);
  269.  
  270.     if (Nntp_port && !strcmp(serv,"nntp"))
  271.       return htons((unsigned short)Nntp_port);
  272.  
  273.     if (srvp == NULL)
  274.       return (unsigned short)0;
  275.     return (unsigned short)srvp->s_port;
  276. #endif    /* NONETDB */
  277.     }
  278. }
  279.  
  280. /*
  281.  * given a host name (either name or internet address) and service name
  282.  * (or port number) (both in ASCII), give us a TCP connection to the
  283.  * requested service at the requested host (or give us FAIL).
  284.  */
  285. get_tcp_conn(host, serv)
  286.      char    *host, *serv;
  287. {
  288. #ifdef USE_KEEPALIVES
  289.     int            on = 1;
  290. #endif
  291.     static char *fname = "get_tcp_conn: ";
  292.     int            e_save;
  293.     register int    sock;
  294.     unsigned long    **addrlist;
  295.     struct sockaddr_in    sadr;
  296. #ifdef    OLDSOCKET
  297.     struct sockproto    sp;
  298.  
  299.     sp.sp_family    = (unsigned short)AF_INET;
  300.     sp.sp_protocol    = (unsigned short)IPPROTO_TCP;
  301. #endif    /* OLDSOCKET */
  302.  
  303.     if ((addrlist = name_to_address(host)) == NULL)
  304.       return NOHOST;
  305.  
  306.     sadr.sin_family = (unsigned short)AF_INET;    /* Only internet for now */
  307.     if ((sadr.sin_port = gservice(serv, "tcp")) == 0)
  308.       return NOSERVICE;
  309.  
  310.     for(; *addrlist != NULL; addrlist++) {
  311.     memcpy((caddr_t)&sadr.sin_addr, (caddr_t)*addrlist,
  312.            sizeof(sadr.sin_addr));
  313.  
  314. #ifdef    OLDSOCKET
  315.     if ((sock = socket(SOCK_STREAM, &sp, NULL, 0)) < 0)
  316.       return FAIL;
  317.  
  318.     if (connect(sock, (struct sockaddr *)&sadr) < 0) {
  319. #else
  320.     if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  321.       return FAIL;
  322.  
  323.     if (connect(sock, (struct sockaddr *)&sadr, sizeof(sadr)) < 0) {
  324. #endif    /* OLDSOCKET */
  325.         e_save = errno;
  326.         (void) close(sock);    /* dump descriptor */
  327.         errno = e_save;
  328.     } else {
  329. #ifdef USE_KEEPALIVES
  330.         if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
  331.                (char *)&on, sizeof(on)) == FAIL)
  332.           log(LOG_INFO, fname,
  333.           "%s%s[%s]: setsockopt KEEPALIVE: %s\n",
  334.           Host.name, inet_ntoa(sadr.sin_addr), errmsg(errno));
  335. #endif
  336.         return sock;
  337.     }
  338.     }
  339.     return FAIL;
  340. }
  341.  
  342. #ifdef DKHOST
  343.  
  344. /*
  345.  * get_dk_conn -- get a DKHOST connection to an NNTP server
  346.  *
  347.  *    Parameters:    "machine is the name of the NNTP server.
  348.  *
  349.  *    Returns:    file descriptor for the service, or a "-1" in
  350.  *            case of failure.
  351.  *
  352.  *    Side effects:    connects to server.
  353.  *
  354.  *    NOTE: "machine" has to have an entry in the dkhosts file on the
  355.  *        client, or DKHOST nntplink will bomb
  356.  *
  357.  */
  358.  
  359. get_dk_conn(machine)
  360. char *machine;
  361. {
  362. #ifdef DKR_BLOCK
  363. #ifdef DKR_TIME
  364.     static short dkrmode[3] = {DKR_BLOCK|DKR_TIME, 0, 0};
  365. #endif
  366. #endif
  367.     static short timeout=500;       /* read timeout in ms */
  368.     char *maphost(), *dialstring;
  369.     int dkfd;
  370.     /*    if( (dialstring = maphost( machine, 'f', "nntp", "", "-g:%f:-u:%u" )) == (char *)NULL )  */
  371.     if( (dialstring = maphost( machine, 'f', "nntp", "", "-g:%f" )) == (char *)NULL )
  372.       return(-1);
  373.     if( (dkfd = dkdial(dialstring)) >= 0 ) {
  374. #ifdef TCDKITIME
  375.     ioctl(dkfd, TCDKITIME, &timeout);
  376. #endif
  377. #ifdef DIOCRMODE
  378.     ioctl(dkfd, DIOCRMODE, dkrmode);
  379. #endif
  380.     } else
  381.       dkfd = -1;
  382.     return(dkfd);
  383. }
  384. #endif /* DKHOST */
  385.